home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Applications / Alpha.5.96 folder / Misc / AE Builder⁄Printer Doc.text < prev    next >
Encoding:
Text File  |  1994-07-08  |  27.4 KB  |  713 lines  |  [TEXT/MSWD]

  1.     The AppleEvent Builder/Printer    
  2.  
  3.     The AppleEvent Builder/Printer    
  4.  
  5. Page i        15 July 1992
  6.  
  7.  
  8. 7/8/94    Apple Confidential    Page i
  9.  
  10.  
  11.         
  12.  
  13.     The AppleEvent Builder/Printer    
  14.  
  15.     The AppleEvent Builder/Printer    
  16.  
  17. Page i    Apple Confidential    15 July 1992
  18.  
  19.  
  20. 7/8/94    Apple Confidential    Page i
  21.  
  22.  
  23.     The AppleEvent Builder/Printer    
  24.  
  25. 15 July 1992        Page i
  26.  
  27.  
  28.     The AppleEvent Builder/Printer    
  29.  
  30.     The AppleEvent Builder/Printer
  31.  
  32.  
  33. Page i        15 July 1992
  34.  
  35.  
  36. 15 July 1992        Page i
  37.  
  38.  
  39.     The AppleEvent Builder/Printer
  40.  
  41. 15 July 1992        Page i
  42.  
  43.  
  44. DocTitle    DraftNum    7/8/94
  45.  
  46. i    VOLUME_OR_PART_IDENTIFIER
  47.  
  48.         I N D E X    i
  49.  
  50. DocTitle    DraftNum    7/8/94
  51.  
  52.  
  53. Apple Events    The Æ Builder/Printer
  54. Version 1.3.3
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70. Jens Peter Alfke
  71. 11 October 1993
  72. AppleScript Team
  73. © Apple Computer, Inc. 1991–1993
  74.  
  75. Contents
  76. Contents    iii
  77. Introduction    1
  78. OK, What Is It?    1
  79. What’s New?    2
  80. How To Call the Functions    3
  81. AEBuild    3
  82. AEBuildParameters    4
  83. AEBuildAppleEvent    4
  84. AEPrint    5
  85. Descriptor-String Syntax    6
  86. Basic Types    6
  87. Coercion    7
  88. Lists    8
  89. Records    8
  90. Apple Events    9
  91. Substituting Parameters    10
  92. Descriptor-String Grammar    11
  93. An Example & Timing Comparison    13
  94. C Code Using Object-Packing Library    13
  95. Descriptor String    15
  96. AEBuild Call    16
  97. Timing Conclusions    17
  98. The Demo Program    18
  99. The Header Files    19
  100. AEBuild.h    19
  101. AEBuildGlobals.h    20
  102. AEPrint.h    20
  103.  
  104. Introduction
  105. OK, What Is It?
  106. Even with the helpful Object Support Library routines that assemble common 
  107. Apple event object descriptors, building descriptors and events is still a pain. I’ve 
  108. written a library of two functions that make it quick and easy to build or display 
  109. Apple event descriptors and the Apple events themselves.
  110. The AEBuild function takes a format string — a description in a very simple 
  111. language of an Apple event descriptor — and generates a real descriptor (which 
  112. could be a record or list or event) out of it. The AEPrint function does the reverse: 
  113. given an Apple event descriptor, list or record, it prettyprints it to a string. (The 
  114. resulting string, if sent to AEBuild, would reproduce the original AEDesc 
  115. structure.)
  116. AEBuild can plug variable parameters into the structures it generates — as with 
  117. printf, all you do is put marker characters in the format string and supply the 
  118. parameter values as extra function arguments.
  119. The benefits of using this library are fourfold:
  120.     i    It’s easier for you to write the code to build Apple event structures. You 
  121. only have to remember one function call and a few simple syntax rules. 
  122. Your resulting code is also easier to understand.
  123.     i    As of version 1.2, your code is even faster: AEBuild is three to four times 
  124. as fast as the regular Apple Event Manager routines at constructing 
  125. complex structures. (Your mileage may vary.)
  126.     i    Your code is smaller: the code for AEBuild and the AEStream library is 
  127. about 6k in size, and the overhead for each call is minimal. (Most of the 
  128. descriptor string consists of the same four-letter codes you’d be using in 
  129. your program code anyway, and the strings can even be stored in 
  130. resources for more code savings.)
  131.     i    AEPrint helps in debugging programs, by turning mysterious AEDesc 
  132. structures into human-readable text.
  133.  What’s New?
  134. In version 1.3:
  135. •    A new function, AEPrintSize, computes how long the string built by AEPrint 
  136. would be, without actually creating it. This is useful if you want to allocate 
  137. storage for the string dynamically.
  138. •    AEPrint no longer truncates hex dumps (of unknown descriptors) after 32 
  139. bytes.
  140. And in version 1.3.2:
  141. •    AEPrint no longer uses the stdio library. This should help reduce code size 
  142. (and eliminate some problems in code resources) but to do it I had to cripple 
  143. floating-point display. Floating-point descriptors now print as the integer part 
  144. followed by “.XXXX”.
  145. And in version 1.3.3:
  146. •    After a brilliant suggestion by Rob Dye, AEPrint now uses the built in float-
  147. to-text coercion to display floating-point descriptors.
  148. •    Fixed a possible problem with AEBuild input strings containing Return 
  149. characters, in the MPW version of the library.
  150. How To Call the Functions
  151. These are all C functions. They all take variable number s of arguments, so they’d 
  152. be difficult or impossible to call from Pascal, anyway. (And remember, kids: there 
  153. are no Pascal compilers for the PowerPC chip…)
  154. AEBuild
  155.  
  156. OSErr
  157.     AEBuild(  AEDesc *desc, const char *descriptorStr, ... ),
  158.     vAEBuild( AEDesc *desc, const char *descriptorStr, void *args );
  159.  
  160. AEBuild reads a null-terminated descriptor string (usually a constant, although it 
  161. could come from anywhere), parses it and builds a corresponding AEDesc 
  162. structure. (Don’t worry, I’ll describe the syntax of the descriptor string in the 
  163. next section.) If the descriptor string contains magic parameter-substitution 
  164. characters (“@”) then corresponding values of the correct type must be supplied 
  165. as function arguments, just as with printf.
  166. (vAEBuild is analogous to vprintf: Instead of passing the parameters along with 
  167. the function, you supply a va_list, as defined in <stdarg.h>, that points to the 
  168. parameter list. It’s otherwise identical.)
  169. AEBuild returns an OSErr. Any errors returned by Apple Event Manager routines 
  170. while building the descriptor will be sent back to you. The most likely results are 
  171. memFullErr and errAECoercionFail. Also likely is aeBuildSyntaxErr, resulting 
  172. from an incorrect descriptor string. (Make sure to debug your descriptor strings, 
  173. perhaps using the demo application, before you put them in programs!)
  174. The basic version of AEBuild just reports that a syntax error occurred, without 
  175. giving any additional information. If you want to know more (perhaps the string 
  176. came from a user, to whom you’d like to report a helpful error message) you can 
  177. use the other version of the library. This version includes a wee bit of extra code, 
  178. and two global variables that will contain useful information after a syntax error:
  179.  
  180. extern AEBuild_SyntaxErrType
  181.     AEBuild_ErrCode;
  182. extern long
  183.     AEBuild_ErrPos;
  184.  
  185. AEBuild_ErrCode is an enumerated value that will contain a specific error code. 
  186. The error codes are defined in AEBuild.h. AEBuild_ErrPos will contain the index 
  187. into the descriptor string at which the error occurred: usually one character past 
  188. the end of the offending token.
  189. AEBuildParameters
  190.  
  191. OSErr    AEBuildParameters(  AppleEvent *event, const char *descriptorStr, ... );
  192.  
  193. AEBuildParameters adds parameters and/or attributes to an existing Apple 
  194. event. descriptorStr specifies the parameters (required and optional) and 
  195. attributes. Its syntax is described below (see especially the Apple Event 
  196. Descriptor Strings subsection); it’s almost the same as the syntax for AEBuild, 
  197. with a few additions and modifications.
  198. (vAEBuildParameters is analogous to vprintf: Instead of passing the parameters 
  199. along with the function, you supply a va_list, as defined in <stdarg.h>, that 
  200. points to the parameter list. It’s otherwise identical.)
  201. AEBuildAppleEvent
  202.  
  203. AEBuildAppleEvent(    AEEventClass theClass, AEEventID theID,
  204.                     DescType addressType, void *addressData, long addressLength,
  205.                     short returnID, long transactionID,
  206.                     AppleEvent *event,
  207.                     const char *descriptorStr, ... );
  208.  
  209. AEBuildAppleEvent is like AEBuild but builds an Apple event, including 
  210. parameters and attributes. Or, you could say that it’s like AEBuildParameters but 
  211. creates the event from scratch.
  212. Most of the parameters are just like the parameters to AECreateAppleEvent, 
  213. although you pass the target address data directly, instead of via a pre-built 
  214. descriptor. The resulting Apple event will appear in the event parameter.
  215. descriptorStr specifies the parameters (required and optional) and attributes. 
  216. The syntax is described below (see especially the Apple Event Descriptor Strings 
  217. subsection); it’s almost the same as the syntax for AEBuild, with a few additions 
  218. and modifications.
  219. (vAEBuildAppleEvent is analogous to vprintf: Instead of passing the parameters 
  220. along with the function, you supply a va_list, as defined in <stdarg.h>, that 
  221. points to the parameter list. It’s otherwise identical.)
  222. AEPrint
  223.  
  224. OSErr AEPrint( AEDesc *desc, char *bufStr, long bufSize );
  225.  
  226. AEPrint reads the Apple event descriptor desc and writes a corresponding 
  227. descriptor string into the string pointed to by bufStr. It will write no more than 
  228. bufSize characters, including the trailing null character. Any errors returned by 
  229. Apple Event Manager routines will be returned to the caller; this isn’t very likely 
  230. unless the AEDesc structure is somehow corrupt.
  231. The descriptor string produced, if sent to AEBuild, will build a descriptor 
  232. identical to the original one. AEPrint tries to detect AERecords that have been 
  233. coerced to other types and print them as coerced records. Structures of unknown 
  234. type that can’t be coerced to AERecords are dumped as hex data.
  235. AEPrint can also print complete Apple events as well as regular descriptors. The 
  236. syntax of the resulting string for an event is like that used by AEBuildParameters 
  237. and AEBuildAppleEvent, except that:
  238. •    The string begins with the event class and ID separated by a backslash.
  239. •    the parameter list is surrounded by curly braces.
  240. •    Attributes are also displayed; they look like parameters but are preceded by 
  241. “&”s.
  242. u    The builder functions do not accept this event syntax yet.  u
  243. AEPrintSize
  244.  
  245. OSErr AEPrintSize( AEDesc *desc, long *bufSizeNeeded );
  246.  
  247. AEPrintSize computes the buffer size that AEPrint would require if given the 
  248. same descriptor. (The size is equal to the string length, plus 1 byte for the trailing 
  249. null.) This is handy for pre-flighting AEPrint, if you want to allocate the buffer 
  250. dynamically  instead of relying on one of fixed size .
  251. Descriptor-String Syntax
  252. The real meat of all this, of course, is the syntax of the descriptor strings. It’s 
  253. pretty simple: basic data types like numbers and strings can be described 
  254. directly, and then built up into lists and records. I’ve even provided a pseudo-
  255. BNF grammar (next section) for those of you who actually enjoy reading those 
  256. things.
  257. Basic Types
  258. The fundamental data types are:
  259.  
  260. Type    Examples    Type-code    Description
  261. Integer    1234
  262. -5678    'long' or
  263. 'shor'    A sequence of decimal digits,
  264. optionally preceded by a minus
  265. sign.
  266. Enum/Type
  267. Code    whos
  268. longint
  269. 'long'
  270. <=
  271. '8-)'
  272. ‘ZQ 5’
  273. m    'enum'
  274. (Use coercion
  275. to change to
  276. 'type')    A magic four-letter code. Will be
  277. truncated or padded with spaces
  278. to exactly four characters. If you
  279. put straight or curly single-
  280. quotes around it, it can contain
  281. any characters. If not, it can’t
  282. contain any of: @‘'“”:-,([{}])
  283. and can’t begin with a digit.
  284. String    “A String.”
  285. “Multiple lines
  286. are okay.”    'TEXT'    Any sequence of characters
  287. within open and close curly
  288. quotes. Won’t be null-terminated.
  289. Hex Data    «4170706C65»
  290. «0102 03ff
  291.  e b 6 c»    ??
  292. (Must be
  293. coerced to
  294. some type)    An even number of hex digits
  295. between French quotes (Option-
  296. \, Option-Shift-\). Whitespace is
  297. ignored.
  298. u    Yes, you have to use the actual four-letter codes for enums, type codes, 
  299. keywords and object types, instead of the mnemonic constants. Luckily the 
  300. codes are semi-mnemonic anyway. I did it this way to avoid the massive 
  301. overhead, both in code size and execution speed, of a symbol table. You can 
  302. find the definitions of the constants in the text file “AEObjects.p”, which is 
  303. part of the Apple Events Object Support Library.  u
  304. Coercion
  305. Any basic element (except a hex string) by itself is a descriptor, whose 
  306. descriptorType is as given in the table. You can coerce a basic element to a 
  307. different type by putting it in parentheses with a type-code placed before it. Here 
  308. are some examples:
  309.  
  310.     sing(1234)
  311.     type(line)
  312.     long(CODE)
  313.     hexd(“A String”)
  314.     'blob'(«4170706C65»)
  315.  
  316. u    Coercions of numeric values are effected by calling AECoerceDesc; if the 
  317. coercion fails, you’ll get an errAECoercionFail error returned to you. 
  318. Coercions of other types just replace the descriptorType field of the AEDesc.  u
  319. u    Hex strings must be coerced to something, since they have no intrinsic type.  u
  320. You can also coerce nothing, to get a descriptor with zero-length data:
  321.  
  322.     emty()
  323.  
  324. Even the type can be omitted, leaving just (), in which case the type is 'null'.
  325. Lists
  326. To make an AEDescList, just enclose a comma-separated list of descriptors in 
  327. square brackets. For example:
  328.  
  329.     [123, -456, “et cetera”]
  330.     [sing(1234), long(CODE),
  331.      [“wheels”, “within wheels”]]
  332.     []
  333.  
  334. The elements of a list can be of different types, and a list can contain other lists or 
  335. records (see below) as elements.
  336. Lists cannot be coerced to other types; the type of a list is always 'list'.
  337. Records
  338. An AERecord is indicated by a comma-separated list of elements enclosed in curly 
  339. braces. Each element of a record consists of a keyword (a type-code, as described 
  340. under Basic Types) followed by a “:”, followed by a value, which can be any 
  341. descriptor: a basic type, a list or another record. For example:
  342.  
  343.     {x:100, y:-100}
  344.     {'origin': {x:100, y:-100}, extent: {x:500, y:500},
  345.      cont: [1, 5, 25]}
  346.     {}
  347.  
  348. The default type of a record is 'reco'. Many of the Apple Events Object Model 
  349. structures are AERecords that have been coerced to some other data type, like 
  350. 'indx' or 'whos'. You can coerce a record structure to any type by preceding it 
  351. with a type code. For example:
  352.  
  353.     rang{ star: 5, stop: 6}
  354.  
  355. s    Warning    Coercing to an existing type, such as 'bool' or 'TEXT', is a bad 
  356. idea. Anyone parsing the descriptor (including AEPrint) will 
  357. recognize the type and assume that the data has the normal 
  358. interpretation, which in this case it wouldn’t. Bad to awful things 
  359. would happen. Don’t do it.
  360. Apple Events
  361. The syntax of the formatting string for an entire Apple event (as passed to 
  362. AEBuildAppleEvent) is almost identical to that of a record. Each keyed element 
  363. specified in the string becomes a parameter or attribute of the event. The 
  364. differences are:
  365. •    There are no curly-braces at the beginning and end of the string.
  366. •    The character “~” before a parameter keyword makes it optional.
  367. Here’s an example of how to construct an Open Selection event for the Finder:
  368.  
  369.     AliasHandle parent, itemToOpen;
  370.     const OSType finderSignature = 'MACS';
  371.     AppleEvent event;
  372.     OSErr err;
  373.  
  374.     // Construct the aliases here (not shown)
  375.  
  376.     err= AEBuildEppleEvent(
  377.             'FNDR', 'SOPE',
  378.             typeApplSignature, @finderSignature, sizeof(finderSignature),
  379.             kAutoGenerateReturnID, kAnyTransactionID,
  380.             &event,                                        // Event to be created
  381.             "----: alis(@@), fsel: [alis(@@)]",            // Format string
  382.                 parent,                                    // param for 1st @@
  383.                 itemToOpen                                // param for 2nd @@
  384.     );
  385. Substituting Parameters
  386. To plug your own values into the midst of a descriptor, use the magic “@” 
  387. character. You can use “@” anywhere you can put a basic element like an integer. 
  388. Each “@” is replaced by a value taken from the parameter list sent to the AEBuild 
  389. function. The type of value created depends on the context in which the “@” is 
  390. used: in particular, how it’s coerced.
  391.  
  392. Type Coerced to:    Type of fn parameter read:    Comments:
  393. No coercion    AEDesc*    A plain “@” will be replaced with a
  394. descriptor parameter.
  395. Numeric (bool, shor,
  396. long, sing, doub, exte)    short, short, long, float,
  397. short double, double    Remember that THINK C’s double
  398. corresponds to type 'exte'!
  399. TEXT    char*    Pointer to a null-terminated C string.
  400. Any other type    long followed by void*    Expects a length parameter followed by
  401. a pointer to the descriptor data.
  402. s    Important    Note particularly: that TEXT parameters must be null-terminated 
  403. strings, although the resulting descriptor data will not be null-
  404. terminated; and that the general case expects two parameters: the 
  405. data’s size and location.   s
  406. In addition, you can substitute data from a handle by using two @ signs. An “@@” 
  407. parameter will read a single handle from the parameter list and use the data 
  408. pointed to by that handle as the value of the descriptor. The “@@” must be 
  409. coerced so that AEBuild will know what type to make the descriptor; however, 
  410. the type coerced to can be anything (the table above is ignored.)
  411. This mechanism is still a bit limited, and may well be improved in the future.
  412. Descriptor-String Grammar
  413. Since no language, however small, can be taken seriously unless it comes fully 
  414. equipped with a formidable-looking BNF grammar specification, I here present 
  415. one. No attempt has been made to prevent Messrs. Backus and/or Naur from 
  416. rolling over in their respective graves.
  417. Character Classification:
  418. whitespace    ‘ ’, ‘\r’, ‘\n’, ‘\t’
  419. digit    0 … 9
  420. paren, bracket,
  421. braces    (, ), [, ], {, }
  422. single-quote    '
  423. double quotes    “, ”
  424. hex quotes    «, »
  425. colon    :
  426. comma    ,
  427. at-sign    @
  428. identchar    any other printable character
  429. Tokens:
  430. ident ::=    identchar (identchar | digit)*    —Padded/truncated
  431.     ' character* '    to exactly 4 chars
  432. integer ::=    [ - ] digit+    —Just as in C
  433. string ::=    “ (character)* ”
  434. hexstring ::=    « (hexdigit | whitespace)* »    —Even no. of digits, please
  435. Grammar Rules for AEBuild:
  436. formatstring ::=    obj    —This is the top level of syntax
  437. obj ::=    data    —Single AEDesc; shortcut for (data)
  438.     structure    —Un-coerced structure
  439.     ident structure    —Coerced to some other type
  440. structure ::=    ( data )    —Single AEDesc
  441.     [ objectlist ]    —AEList type
  442.     { keywordlist }    —AERecord type
  443. objectlist ::=    «blank»    —Comma-separated list of things
  444.     obj [ , obj ]*
  445. keywordpair ::=    ident : obj    —Keyword/value pair
  446. keywordlist ::=    «blank»    —List of said pairs
  447.     keywordpair [ , keywordpair ]*
  448. data ::=    @    —Gets appropriate data from fn param
  449.     integer    —'shor' or 'long' unless coerced
  450.     ident    —A 4-char type code ('type') unless coerced
  451.     string    —Unterminated text; 'TEXT' type unless coerced
  452.     hexstring    —Raw hex data; must be coerced to some type!
  453. Grammar Rules for AEBuildAppleEvent:
  454. eventstring ::=    evtkeywordlist    —Top level syntax for AEBuildAppleEvent
  455. evtkeywordpair ::=    [~] ident : obj    —Keyword/value pair
  456. evtkeywordlist ::=    «blank»    —List of said pairs
  457.     evtkeywordpair [ , evtkeywordpair ]*
  458. There. Now it’s all crystal-clear, right?
  459. An Example & Timing Comparison
  460. As an example, I’ll take a C function to generate an object descriptor (taken from 
  461. a Pascal example in the Object Model ERS, fleshed out and with gobs of error 
  462. checking added) and turn it into a call to AEBuild. The object descriptor we want 
  463. to generate is:
  464. First line of document 'Spinnaker' whose first word is 'April'
  465. and whose second word is 'is'
  466. Then I’ll execute both functions and compare their execution times.
  467. C Code Using Object-Packing Library
  468. OSErr
  469. BuildByHand( AEDesc *dDocument, AEDesc *theResultObj )
  470. {
  471.     OSErr err;
  472.     AEDesc dObjectExamined, dNum, dWord1, dWord2, dAprilText, dIsText,
  473.            dComparison1, dComparison2, dLogicalTerms, dTheTest, dLineOne, dTestedLines;
  474.     
  475.     dObjectExamined.dataHandle =    /* Zero things to start out with so we can safely */
  476.         dNum.dataHandle =                /* execute our fail code if things don't work out */
  477.         dWord1.dataHandle =
  478.         dWord2.dataHandle =
  479.         dAprilText.dataHandle =
  480.         dIsText.dataHandle =
  481.         dComparison1.dataHandle =
  482.         dComparison2.dataHandle =
  483.         dLogicalTerms.dataHandle =
  484.         dTheTest.dataHandle =
  485.         dLineOne.dataHandle =
  486.         dTestedLines.dataHandle =
  487.             NIL;
  488.  
  489.     if( err= AECreateDesc( 'exmn', NIL, 0, &dObjectExamined ) )
  490.         goto fail;
  491.  
  492.     if( err= MakeIndexDescriptor(1,&dNum) )
  493.         goto fail;
  494.     if( err= MakeObjDescriptor( 'word', &dObjectExamined, formIndex, &dNum,
  495.                     false, &dWord1) )
  496.         goto fail;
  497.     if( err= AECreateDesc( 'TEXT', "April", 5, &dAprilText ) )
  498.         goto fail;
  499.  
  500.     AEDisposeDesc(&dNum);
  501.     if( err= MakeIndexDescriptor(2,&dNum) )
  502.         goto fail;
  503.     if( err= MakeObjDescriptor( 'word', &dObjectExamined, formIndex, &dNum,
  504.                     true, &dWord2) )
  505.         goto fail;
  506.     if( err= AECreateDesc( 'TEXT', "is", 2, &dIsText ) )
  507.         goto fail;
  508.  
  509.     if( err= MakeCompDescriptor( '=   ', &dAprilText, &dWord1, true, &dComparison1 ) )
  510.         goto fail;
  511.     if( err= MakeCompDescriptor( '=   ', &dIsText,      &dWord2, true, &dComparison2 ) )
  512.         goto fail;
  513.  
  514.     if( err= AECreateList( NIL, 0, false, &dLogicalTerms ) )
  515.         goto fail;
  516.     if( err= AEPutDesc( dLogicalTerms, 1, dComparison1 ) )
  517.         goto fail;
  518.     if( err= AEPutDesc( dLogicalTerms, 2, dComparison2 ) )
  519.         goto fail;
  520.         
  521.     AEDisposeDesc(&dComparison1);
  522.     AEDisposeDesc(&dComparison2);
  523.     
  524.     if( err= MakeLogicalDescriptor( &dLogicalTerms, 'AND ', true, &dTheTest) )
  525.         goto fail;
  526.     
  527.     if( err= MakeObjDescriptor(classLine,&dDocument,formTest,&dTheTest,true,
  528.                                     &dTestedLines) )
  529.         goto fail;
  530.  
  531.     if( err= MakeIndexDescriptor(1,&dLineOne) )
  532.         goto fail;
  533.     if( err= MakeObjDescriptor( classLine, &dTestedLines, formIndex, &dLineOne,
  534.             true, theResultObj ) )
  535.         goto fail;
  536.     return noErr;
  537.     
  538. fail:                                            /* Clean up in case we couldn't build it */
  539.     AEDisposeDesc(theResultObj);
  540.     AEDisposeDesc(&dObjectExamined);
  541.     AEDisposeDesc(&dNum);
  542.     AEDisposeDesc(&dWord1);
  543.     AEDisposeDesc(&dWord2);
  544.     AEDisposeDesc(&dAprilText);
  545.     AEDisposeDesc(&dIsText);
  546.     AEDisposeDesc(&dComparison1);
  547.     AEDisposeDesc(&dComparison2);
  548.     AEDisposeDesc(&dLogicalTerms);
  549.     AEDisposeDesc(&dTheTest);
  550.     AEDisposeDesc(&dLineOne);
  551.     AEDisposeDesc(&dTestedLines);
  552.     
  553.     return err;
  554. }
  555.  
  556. MPW 3.2b5 C compiled this into 816 bytes of object code.
  557. I found that the average time to execute this function was 0.0188 seconds 
  558. (Quadra 700) or 0.0113 seconds (IIfx).† Use this figure for comparison only; your 
  559. times may vary. The timing is especially dependent on the number of blocks in 
  560. the heap, since so many block allocations and disposals are happening.
  561. Descriptor String
  562. obj{ want:type('line'),
  563.      from: obj{ want: type('line'), from: @, form: 'test',
  564.                 seld: logi{
  565.                            term: [comp{ relo:=, obj1:“April”,
  566.                                         obj2:
  567.                               obj{ want:type('word'), from:exmn(), form:indx, seld:1 }},
  568.                                   comp{ relo:=, obj1:“is”,
  569.                                         obj2:
  570.                               obj{ want:type('word'), from:exmn(), form:indx, seld:2 }}
  571.                                  ],
  572.                            logc:AND
  573.                          }
  574.               },
  575.      form: 'indx',
  576.      seld: 1
  577. }
  578.  
  579. AEBuild Call
  580. char descriptor[] =                /* Same descriptor string as above. Note clever */
  581. "obj{ want:type('line'),"        /* method used to break string across lines. */
  582.     "from: obj{ want: type('line'), from: @, form: 'test',"        /* Note parameter here */
  583.                "seld: logi{"
  584.                           "term: [comp{ relo:=, obj1:“April”,"
  585.                                        "obj2:"
  586.                              "obj{ want:type('word'), from:exmn(), form:indx, seld:1 }},"
  587.                                  "comp{ relo:=, obj1:“is”,"
  588.                                        "obj2:"
  589.                              "obj{ want:type('word'), from:exmn(), form:indx, seld:2 }}"
  590.                                 "],"
  591.                           "logc:AND"
  592.                         "}"
  593.              "},"
  594.     "form: 'indx',"
  595.     "seld: 1"
  596. "}";
  597.  
  598. void PackWordDesc( AEDesc *dDocumentObject )    /* “Spinnaker” descriptor is a parameter */
  599. {
  600.     err = AEBuild(&theResultObj,
  601.                     descriptorString,
  602.                     dDocumentObject);                    /* AEDesc* parameter for "@" */
  603. }
  604.  
  605. MPW 3.2b5 C compiled this into 42 bytes of object code, plus 310 bytes of data 
  606. storage for the string.
  607. I found that the average time to execute this function was 0.0049 seconds 
  608. (Quadra 700) or 0.0070 seconds (IIfx). Use this figure for comparison only; your 
  609. times may vary. The timing is dependent on the number of blocks in the heap, 
  610. since heap blocks are being allocated and resized.
  611. Timing Conclusions
  612. With previous versions of this library, there was a 70% increase in execution time 
  613. when using the AEBuild routine. After delivering the bad news, I wrote:
  614. However, if speed does become an issue, there is always the option of 
  615. turbocharging AEBuild by having it directly build descriptors without going 
  616. through the Apple Event Manager functions at all. This would save an incredible 
  617. number of Memory Manager calls and probably increase performance 
  618. severalfold. Anyone using AEBuild will get all these improvements for free.
  619. This is exactly what I did in version 1.1. In fact, I wrote a library (AEStream) to 
  620. do it, so you can do it too. It’s easy.
  621. AEBuild is now 1.5 to 4 times as fast (depending on CPU) as the using the Apple 
  622. Event Manager and/or Object Packing Library routines. (This means that 
  623. AEStream was responsible for a threefold speed-up in AEBuild. Not bad, when 
  624. you take into account other overhead like parsing the format string!)
  625. Needless to say, if you were already using AEBuild you get this speed increase 
  626. absolutely free. Enjoy!
  627. The Demo Program
  628. I’ve included a demonstration program in the distribution. This is a program I 
  629. used to debug the library. It reads a line of input, uses AEBuild to translate it into 
  630. an AEDesc, uses AEPrint to translate the AEDesc back into a string, and prints 
  631. each resulting string. Error codes are reported, including syntax-error messages. 
  632. The source code is provided in case you want to see how the functions are called.
  633. s    Warning    The demo tool does not handle parameter substitution (the “@” 
  634. character). If you try to substitute parameters, messy and 
  635. unpleasant things may happen. Use some numeric value in place 
  636. of parameters, and then replace it with “@”s after you paste the 
  637. string into your program.  s
  638. The Header Files
  639. Here for your convenience are printouts of the header files as of 21 July 1992.
  640. AEBuild.h
  641. #define aeBuild_SyntaxErr    12345            /* Let's get an Official OSErr code someday */
  642.  
  643. typedef enum{                                /* Syntax Error Codes: */
  644.     aeBuildSyntaxNoErr = 0,                        /* (No error) */
  645.     aeBuildSyntaxBadToken,                        /* Illegal character */
  646.     aeBuildSyntaxBadEOF,                            /* Unexpected end of format string */
  647.     aeBuildSyntaxNoEOF,                            /* Unexpected extra stuff past end */
  648.     aeBuildSyntaxBadNegative,                    /* "-" not followed by digits */
  649.     aeBuildSyntaxMissingQuote,                    /* Missing close "'" */
  650.     aeBuildSyntaxBadHex,                            /* Non-digit in hex string */
  651.     aeBuildSyntaxOddHex,                            /* Odd # of hex digits */
  652.     aeBuildSyntaxNoCloseHex,                        /* Missing "»" */
  653.     aeBuildSyntaxUncoercedHex,                    /* Hex string must be coerced to a type */
  654.     aeBuildSyntaxNoCloseString,                    /* Missing "”" */
  655.     aeBuildSyntaxBadDesc,                        /* Illegal descriptor */
  656.     aeBuildSyntaxBadData,                        /* Bad data value inside (…) */
  657.     aeBuildSyntaxNoCloseParen,                    /* Missing ")" after data value */
  658.     aeBuildSyntaxNoCloseBracket,                /* Expected "," or "]" */
  659.     aeBuildSyntaxNoCloseBrace,                    /* Expected "," or "}" */
  660.     aeBuildSyntaxNoKey,                            /* Missing keyword in record */
  661.     aeBuildSyntaxNoColon,                        /* Missing ":" after keyword in record */
  662.     aeBuildSyntaxCoercedList,                    /* Cannot coerce a list */
  663.     aeBuildSyntaxUncoercedDoubleAt                /* "@@" substitution must be coerced */
  664. } AEBuild_SyntaxErrType;
  665.  
  666. // In all the "v..." functions, the "args" parameter is really a va_list.
  667. // It's listed as void* here to avoid having to #include stdarg.h.
  668.  
  669. // Building a descriptor:
  670.  
  671. OSErr
  672.     AEBuild(  AEDesc *dst, const char *src, ... ),
  673.     vAEBuild( AEDesc *dst, const char *src, const void *args );
  674.  
  675. // Adding a parameter to an Apple event:
  676.  
  677. OSErr
  678.     AEBuildParameters( AppleEvent *event, const char *format, ... ),
  679.     vAEBuildParameters( AppleEvent *event, const char *format, const void *args );
  680.  
  681. // Building an entire Apple event:
  682.  
  683. OSErr
  684.     AEBuildAppleEvent( AEEventClass theClass, AEEventID theID,
  685.                         DescType addressType, const void *addressData, long addressLength,
  686.                         short returnID, long transactionID, AppleEvent *result,
  687.                         const char *paramsFmt, ... ),
  688.     vAEBuildAppleEvent( AEEventClass theClass, AEEventID theID,
  689.                         DescType addressType, const void *addressData, long addressLength,
  690.                         short returnID, long transactionID, AppleEvent *resultEvt,
  691.                         const char *paramsFmt, const void *args );
  692. AEBuildGlobals.h
  693. /*
  694.  *    AEBuildGlobals.h                            Copyright ©1991 Apple Computer, Inc.
  695.  */
  696.  
  697.  
  698. extern AEBuild_SyntaxErrType
  699.     AEBuild_ErrCode;                    /* Examine after AEBuild returns a syntax error */
  700. extern long
  701.     AEBuild_ErrPos;                    /* Index of error in format string */
  702. AEPrint.h
  703. /*
  704.  *    AEPrint.h                                        Copyright ©1991 Apple Computer, Inc.
  705.  */
  706.  
  707. OSErr AEPrint( AEDesc *desc, char *bufStr, long bufSize );
  708.  
  709.  
  710. † Yes, it really took half again as long on a Quadra! I think that cache flushing during the PACK 
  711. call is responsible. (It barely slows down at all when you disable the caches.)
  712.  
  713.